#include "Rp2Object.h"
#include "Rp2Controller.h"

using namespace Rp2;

const Rtti Object::TYPE("Rp2.Object",0);
unsigned int Object::ms_uiNextID = 0;

//---------------------------------------------------------------------------------------------------
Object::Object()
{
	m_iReferences = 0;
	m_uiID = ms_uiNextID++;

}
//---------------------------------------------------------------------------------------------------
Object::~Object()
{
    // This assert traps the case when someone tries 'delete spkObject'
    // for a smart-pointer-based object.  Instead, use 'spkObject = 0'.
	assert(m_iReferences == 0);

	DetachAllControllers();

}
//---------------------------------------------------------------------------------------------------
void Object::DecrementReferences()
{
	if (--m_iReferences == 0)
	{
		delete this;
	}
}
//---------------------------------------------------------------------------------------------------
// controllers
//---------------------------------------------------------------------------------------------------
int Object::GetControllerQuantity () const
{
    return (int)m_kControllers.size();
}
//---------------------------------------------------------------------------------------------------
Controller* Object::GetController (int i) const
{
    assert(0 <= i && i < (int)m_kControllers.size());
    return StaticCast<Controller>(m_kControllers[i]);
}
//---------------------------------------------------------------------------------------------------
void Object::AttachController(Controller* pkController)
{
    // Controllers may not be controlled.  This avoids arbitrarily complex
    // graphs of Objects.  It is possible to allowed controlled controllers,
    // but modify and proceed at your own risk...
	if (IsDerived(Controller::TYPE))
	{
		assert(false);
		return;
	}

	// controller must exist
	if (!pkController)
	{
		assert(pkController);
		return;
	}

    // check if controller is already in the list
    for (int i = 0; i < (int)m_kControllers.size(); i++)
    {
        if (pkController == m_kControllers[i])
        {
            // controller already exists, nothing to do
            return;
        }
    }

    // Bind the controller to the object.
    pkController->SetObject(this);

    // Controller not in current list, add it.
    m_kControllers.push_back(pkController);
}
//---------------------------------------------------------------------------------------------------
void Object::DetachController(Controller* pkController)
{
    std::vector<ObjectPtr>::iterator pkIter = m_kControllers.begin();
    for (/**/; pkIter != m_kControllers.end(); pkIter++)
    {
        if (pkController == *pkIter)
        {
            // Unbind the controller from the object.
            pkController->SetObject(0);

            // Remove the controller from the list.
            m_kControllers.erase(pkIter);

            return;
        }
    }
}
//---------------------------------------------------------------------------------------------------
void Object::DetachAllControllers()
{
    for (int i = 0; i < (int)m_kControllers.size(); i++)
    {
        // Unbind the controller from the object.
        Controller* pkController = StaticCast<Controller>(m_kControllers[i]);
        pkController->SetObject(0);
    }
    m_kControllers.clear();
}
//---------------------------------------------------------------------------------------------------
bool Object::UpdateControllers(double dAppTime)
{
	bool bSomeoneUpdated = false;
    for (int i = 0; i < (int)m_kControllers.size(); i++)
    {
        Controller* pkController = StaticCast<Controller>(m_kControllers[i]);
        if (pkController->Update(dAppTime))
        {
            bSomeoneUpdated = true;
        }
    }
    return bSomeoneUpdated;	
}
//---------------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------------
// name-id system
//---------------------------------------------------------------------------------------------------
Object* Object::GetObjectByName (const std::string& rkName)
{
    if (rkName == m_kName)
    {
        return this;
    }

    for (int i = 0; i < (int)m_kControllers.size(); i++)
    {
        if (m_kControllers[i])
        {
            Object* pkFound = m_kControllers[i]->GetObjectByName(rkName);
            if (pkFound)
            {
                return pkFound;
            }
        }
    }

    return 0;
}
//---------------------------------------------------------------------------------------------------
void Object::GetAllObjectsByName (const std::string& rkName,
    std::vector<Object*>& rkObjects)
{
    if (rkName == m_kName)
    {
        rkObjects.push_back(this);
    }

    for (int i = 0; i < (int)m_kControllers.size(); i++)
    {
        if (m_kControllers[i])
        {
            m_kControllers[i]->GetAllObjectsByName(rkName,rkObjects);
        }
    }
}
//---------------------------------------------------------------------------------------------------
Object* Object::GetObjectByID (unsigned int uiID)
{
    if (uiID == m_uiID)
    {
        return this;
    }

    for (int i = 0; i < (int)m_kControllers.size(); i++)
    {
        if (m_kControllers[i])
        {
            Object* pkFound = m_kControllers[i]->GetObjectByID(uiID);
            if (pkFound)
            {
                return pkFound;
            }
        }
    }

    return 0;
}
//---------------------------------------------------------------------------------------------------